﻿namespace Groundwork.Extensions
{
    using System;
    using System.Collections.Generic;
    using Groundwork.Core;
	using System.Threading;
	
    /// <summary>
    /// Object Extensions. These provide a way of checking the object values and performing operations on values.
    /// </summary>
    public static class Objects
    {
   	
        /// <summary>
        /// Checks if the current object is a a numeric type.
        /// </summary>
        /// <param name="value">current value to test</param>
        /// <returns>true or false indicating if the value is numeric</returns>
        public static bool IsNumber(this object value)
        {
            return value is sbyte
                    || value is byte
                    || value is short
                    || value is ushort
                    || value is int
                    || value is uint
                    || value is long
                    || value is ulong
                    || value is float
                    || value is double
                    || value is decimal;
        }

        /// <summary>
        /// Allows you to specify a default value if the current value is null
        /// </summary>
        /// <typeparam name="T">Generic T parameter</typeparam>
        /// <param name="value">value to inspect</param>
        /// <param name="defaultValue">default value to assume</param>
        /// <returns>returns specified default value</returns>
        public static T Default<T>(this object value, T defaultValue) where T : class, new()
        {
            if (value.IsNull())
            {
                return defaultValue;
            }

            return value as T;
        }

        /// <summary>
        /// Checks if the current value is null
        /// </summary>
        /// <param name="value">Value to examine</param>
        /// <returns>true if value is null, false if not</returns>
        public static bool IsNull(this object value)
        {
            if (value == null)
            {
                return true;
            }

            return false;
        }

        /// <summary>
        /// Converts the provided value to the Generic Type provided
        /// </summary>
        /// <typeparam name="T">Type to convert to</typeparam>
        /// <param name="value">value to convert</param>
        /// <param name="outputValue">converted value</param>
        /// <returns>true if conversion was successful</returns>
        public static bool TryConvert<T>(object value, out T outputValue) where T : IConvertible
        {
            outputValue = default(T);
            try
            {
                outputValue = StaticUtility.ConvertTo<T>(value);
            }
            catch
            {
                return false;
            }

            return true;
        }


        /// <summary>
        /// Dynamic Switch statement, switch values are provided by the processing dictionary which is passed in.
        /// </summary>
        /// <typeparam name="TKey">Generic value for key</typeparam>
        /// <param name="value">The value.</param>
        /// <param name="processing">Processing Dictionary</param>
        /// <param name="inputArg">Parameter to pass to delegate method</param>
        /// <example>
        ///   <code><![CDATA[
        /// Dictionary<string, Action<object[]>> proc = new Dictionary<string, Action<object[]>>()
        /// {
        /// 	{"key1", (o) => { string value = (string)o[0]; }},
        /// 	{"key2", (o) => { }}
        /// };
        /// 
        /// string testing = "key1";
        /// testing.Switch<string>(new[] { "value1" }, proc);
        /// ]]></code>
        ///   </example>
        public static void Switch<TKey>(this TKey value, Dictionary<TKey, Action<object[]>> processing, params object[] inputArg)
        {
            if (processing.ContainsKey(value))
            {
                processing[value](inputArg);
            }
        }

        /// <summary>
        /// Dynamic Switch statement, switch values are provided by the processing dictionary which is passed in.
        /// </summary>
        /// <typeparam name="TKey">Generic value for key</typeparam>
        /// <typeparam name="TOutput">Generic value for the output value</typeparam>
        /// <param name="value">The value.</param>
        /// <param name="processing">Processing Dictionary</param>
        /// <param name="inputArg">Parameter to pass to delegate method</param>
        /// <returns>Return value of the Func delegate</returns>
        public static TOutput Switch<TKey, TOutput>(this TKey value, Dictionary<TKey, Func<object[], TOutput>> processing, params object[] inputArg)
        {
            if (processing.ContainsKey(value))
            {
                return processing[value](inputArg);
            }
            return default(TOutput);
        }
    }
}
